﻿import type { RequestOptions } from '@@/plugin-request/request';
import { type RequestConfig } from '@umijs/max';
import { message, notification } from 'antd';
import { refreshTokenApi } from './services/ant-design-pro/api';

// 错误处理方案： 错误类型
enum ErrorShowType {
  SILENT = 0,
  WARN_MESSAGE = 1,
  ERROR_MESSAGE = 2,
  NOTIFICATION = 3,
  REDIRECT = 9,
}
// 与后端约定的响应数据格式
interface ResponseStructure {
  success: boolean;
  data: any;
  errorCode?: number;
  errorMessage?: string;
  showType?: ErrorShowType;
}

/**
 * @name 错误处理
 * pro 自带的错误处理， 可以在这里做自己的改动
 * @doc https://umijs.org/docs/max/request#配置
 */

let pendingRequests = [];
let isRefreshing = false;

export const errorConfig: RequestConfig = {
  // 错误处理： umi@3 的错误处理方案。
  errorConfig: {
    // 错误抛出
    errorThrower: (res) => {
      const { success, data, errorCode, errorMessage, showType } =
        res as unknown as ResponseStructure;
      if (!success) {
        const error: any = new Error(errorMessage);
        error.name = 'BizError';
        error.info = { errorCode, errorMessage, showType, data };
        throw error; // 抛出自制的错误
      }
    },
    // 错误接收及处理
    errorHandler: async (error: any, opts: any) => {
      console.log('[error]', error);
      if (opts?.skipErrorHandler) throw error;
      // 我们的 errorThrower 抛出的错误。
      if (error.name === 'BizError') {
        const errorInfo: ResponseStructure | undefined = error.info;
        if (errorInfo) {
          const { errorMessage, errorCode } = errorInfo;
          switch (errorInfo.showType) {
            case ErrorShowType.SILENT:
              // do nothing
              break;
            case ErrorShowType.WARN_MESSAGE:
              message.warning(errorMessage);
              break;
            case ErrorShowType.ERROR_MESSAGE:
              message.error(errorMessage);
              break;
            case ErrorShowType.NOTIFICATION:
              notification.open({
                description: errorMessage,
                message: errorCode,
              });
              break;
            case ErrorShowType.REDIRECT:
              // TODO: redirect
              break;
            default:
              message.error(errorMessage);
          }
        }
      } else if (error.response) {
        if (error.response.status === 401) {
          if (error.config.url === '/admin/login') {
            return;
          }
          if (error.config.url === '/admin/token/refresh') {
            window.location.href = '/user/login';
            return;
          }

          if (!isRefreshing) {
            isRefreshing = true;
            const refreshToken = localStorage.getItem('refreshToken');
            console.log('[refreshToken]', refreshToken);
            try {
              message.info('登录过期，现在尝试无感重登');
              // setTimeout(async () => {
              const refreshResponse = await refreshTokenApi({
                refreshToken,
              });
              if (refreshResponse) {
                console.log('[refreshResponse]', refreshResponse);
                localStorage.setItem('token', refreshResponse.data.token);
                localStorage.setItem('refreshToken', refreshResponse.data.refreshToken);
                // 重新发起请求
                window.location.reload();
                // if (pendingRequests?.length !== 0) {
                //   pendingRequests.forEach((item) => item?.send());
                //   pendingRequests = [];
                // } else {
                //   return error.response.request.send();
                // }
              }
              console.log('😈refreshResponse', refreshResponse);
              // }, 1000);

              // isRefreshing = false;
            } catch (error) {
              console.error('Refresh Token failed', error);
              window.location.href = '/user/login';
            }
          } else {
            console.log('[error.response.request]', error.response.request);
            pendingRequests.push(error.response.request);
            console.log('😈pendingRequests', pendingRequests);
          }
        }
        // if (error.response?.data?.code === 401) {
        //   message.error('登录过期，请重新登录。');
        //   history.replace('/user/login');
        // }
        // Axios 的错误
        // 请求成功发出且服务器也响应了状态码，但状态代码超出了 2xx 的范围
        else message.error(`请求错误:${error.response.status}`);
      } else if (error.request) {
        // 请求已经成功发起，但没有收到响应
        // \`error.request\` 在浏览器中是 XMLHttpRequest 的实例，
        // 而在node.js中是 http.ClientRequest 的实例
        message.error('None response! Please retry.');
      } else {
        // 发送请求时出了点问题
        message.error('Request error, please retry.');
      }
    },
  },

  // 请求拦截器
  requestInterceptors: [
    (config: RequestOptions) => {
      // 拦截请求配置，进行个性化处理。
      console.log('[config?.url]', config?.url);
      if (
        config?.url?.indexOf('/admin/login') === -1 &&
        config?.url?.indexOf('/admin/token/refresh') === -1
      ) {
        config.headers = {
          ...config.headers,
          Authorization: `Bearer ${localStorage.getItem('token')}`,
        };
      }

      const url = config?.url;
      return { ...config, url };
    },
  ],

  // 响应拦截器
  responseInterceptors: [
    async (response) => {
      // if (response.status === 401) {
      //   const refreshToken = localStorage.getItem('refreshToken');
      //   try {
      //     const refreshResponse = await refreshTokenApi({ refreshToken });
      //     if (refreshResponse) {
      //       localStorage.setItem('token', refreshResponse.token);
      //       localStorage.setItem('refreshToken', refreshResponse.refreshToken);
      //       // 重新发起请求
      //       response.request.headers.Authorization = `Bearer ${refreshResponse.token}`;
      //       return response.request.send();
      //     }
      //   } catch (error) {
      //     console.error('Refresh Token failed', error);
      //     window.location.href = '/user/login';
      //   }
      // }

      console.log('[response]', response);
      if (response?.data?.code === 1) {
        message.error(response?.data?.message);
      }
      return response;
    },
  ],
};
